package server;

import pojo.*;
import util.PokeComparator;
import util.StreamUtil;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * 每一个对象只针对一局游戏的控制，新的一局则新建一个对象
 */
public class GameController {
    //当前的游戏局数
    private int gameNumber;
    private int gamerNumber;
    //参与本局游戏的用户
    private List<Person> gamers;
    //已经抽出来的牌
    private HashMap<Integer, PokeEnum> existPoke = new HashMap<>();
    private List<ObjectOutputStream> outputStreamList;
    private List<ObjectInputStream> inputStreamList;
    private StreamUtil<ServerMessage,ClientMessage> streamUtil;


    public GameController(List<ObjectOutputStream> outputStreamList,List<ObjectInputStream> inputStreamList,int gameNumber,
                          int gamerNumber,List<Person> gamers) {
        this.outputStreamList = outputStreamList;
        this.inputStreamList = inputStreamList;
        this.gameNumber = gameNumber;
        this.gamerNumber = gamerNumber;
        this.gamers = gamers;
        streamUtil = new StreamUtil<>(ClientMessage.class);
    }

    /**
     * 游戏开始后总流程控制
     */
    public int gameBegin() throws IOException, ClassNotFoundException {
        notifyGameBegin();

        //给所有用户发第一张牌，此牌为暗牌
        deal();
        DecisionResult result;
        //给所有用户发第二张牌
        deal();
        result = makeDecision(1);
        if (result.isGameOver()){
            return result.getWinnerIndex();
        }

        //给所有用户发第三张牌
        deal();
        result = makeDecision(2);
        if (result.isGameOver()){
            return result.getWinnerIndex();
        }

        //给所有用户发第四张牌
        deal();
        result = makeDecision(3);
        if (result.isGameOver()){
            return result.getWinnerIndex();
        }

        //给所有用户发第五张牌
        deal();
        result = makeDecision(4);
        if (result.isGameOver()){
            return result.getWinnerIndex();
        }

        //比较牌型大小，决定最终获胜者
        return PokeComparator.getWinner(gamers);
    }

    /**
     * 让玩家开始下注
     */
    private DecisionResult makeDecision(int pokeNumber) throws IOException, ClassNotFoundException {
        int winnerIndex = -1;
        boolean gameOver = false;
        //找出牌面最大的人，由他决定下注
        int decisionMaker = whoMakeDecision(pokeNumber);
        //每一轮下注的金额
        int cost = 0;
        for(int count=0 ; count<gamerNumber ; ){
            int clientIndex = (decisionMaker+count)%gamerNumber;
            System.out.println("### 当前由"+clientIndex+"号玩家下注 ###");
            //检查是否只剩下一个玩家，若是则获胜
            int abandonCount = 0;
            for (int i=0 ; i< gamerNumber ; i++) {
                if (gamers.get(i).isAbandon()){
                    abandonCount++;
                }else {
                    winnerIndex = i;
                }
            }
            if (abandonCount == gamerNumber-1){
                gameOver = true;
                break;
            }


            //检查该玩家是否已经放弃游戏了
            Person gamer = gamers.get(clientIndex);
            if (!gamer.isAbandon()){
                ServerMessage serverMessage = new ServerMessage();
                serverMessage.setType(ServerInstruction.DECISION);
                serverMessage.setDecisionMaker(decisionMaker);
                serverMessage.setTotalCost(gamer.getCost());
                serverMessage.setMoneyLeft(gamer.getMoney()-gamer.getCost());
                serverMessage.setPeople(gamers);
                serverMessage.setGamerNumber(clientIndex);
                serverMessage.setCost(cost);
                //发送消息给客户端
                streamUtil.write(outputStreamList.get(clientIndex),serverMessage);

                //接受客户端返回的下注结果

                ClientMessage clientMessage = streamUtil.read(inputStreamList.get(clientIndex));

                switch (clientMessage.getDecision()){
                    case MAKE_DECISION:

                        //如果有用户加注，需要把之前人下注修改的金额进行数据修复，否则会存在脏数据
                        for(int i=0;i<count;i++){
                            int fixIndex = (decisionMaker+i)%gamerNumber;
                            gamers.get(fixIndex).subCost(cost);
                        }

                        cost = clientMessage.getCost();
                        gamers.get(clientIndex).addCost(cost);
                        decisionMaker = clientIndex;
                        count = 1;
                        break;
                    case SUOHA:
                        gamers.get(clientIndex).setSuoha(true);
                    case FOLLOW:
                        cost = clientMessage.getCost();
                        gamers.get(clientIndex).addCost(cost);
                        count++;
                        break;
                    case ABANDON:
                        gamers.get(clientIndex).setAbandon(true);
                        count++;
                        break;
                }
            }else {
                //已经放弃游戏的直接跳过
                count++;
            }
        }
        return new DecisionResult(gameOver,winnerIndex);
    }

    /**
     * 进行资金结算，将败者的钱加到获胜者的账户里.
     * 并将本局游戏数据清空（cost等数据），为下把游戏进行做准备
     * @param winnerIndex
     */
    public void gameAccount(int winnerIndex){
        Person winner = gamers.get(winnerIndex);
        for (int i=0 ; i< gamers.size() ; i++){
            if ( i == winnerIndex){
                continue;
            }
            winner.addMoney(gamers.get(i).subMoney(gamers.get(i).getCost()));
        }

        for (Person gamer : gamers) {
            gamer.setReady(false);
            gamer.setCost(0);
            gamer.setPokeList(new ArrayList<>());
            gamer.setAbandon(false);
            gamer.setReceivedReadyMessage(false);
            gamer.setSuoha(false);
        }
    }

    public void notifyWinner(int winnerIndex){
        ServerMessage serverMessage = new ServerMessage();
        serverMessage.setPeople(gamers);
        serverMessage.setType(ServerInstruction.WINNER);
        serverMessage.setWinner(winnerIndex);
        for (ObjectOutputStream stream : outputStreamList) {
            try {
                streamUtil.write(stream,serverMessage);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 通知所有玩家游戏开始
     */
    private void notifyGameBegin(){
        ServerMessage serverMessage = new ServerMessage();
        serverMessage.setPeople(gamers);
        serverMessage.setType(ServerInstruction.BEGIN);
        for (ObjectOutputStream stream : outputStreamList) {
            try {
                streamUtil.write(stream,serverMessage);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }



    /**
     * 给每一个人发一张牌
     */
    public void deal(){
        for (int i = 0 ; i < gamerNumber ; i++ ){
            PokeEnum pokeEnum = randomPoke();
            List<PokeEnum> pokeEnumList = gamers.get(i).getPokeList();
            pokeEnumList.add(pokeEnum);
        }
    }

    /**
     * 判断一张扑克是否已经被使用过
     * @param pokeEnum
     * @return
     */
    private boolean exist(PokeEnum pokeEnum){
        if (existPoke.get(pokeEnum.getIndex()) == null){
            return false;
        }else {
            return true;
        }
    }

    /**
     * 把一张扑克添加到已经使用的牌堆里面
     */
    private void addPoke(PokeEnum pokeEnum){
        if (existPoke.get(pokeEnum.getIndex()) != null){
            throw new RuntimeException("当前扑克已被使用，不可重复使用");
        }
        existPoke.put(pokeEnum.getIndex(),pokeEnum);
    }

    /**
     * 随机生成一张扑克牌
     */
    private PokeEnum randomPoke(){
        PokeEnum poke = null;
        while(poke == null){
            //生成一个1-52的随机数，通过这个随机数来获取牌
            int index= (int)(Math.random()*52)+1;
            poke = PokeEnum.getPoke(index);

            //判断一张牌是否已经被使用过，如果没有使用过则放进去，如果已经使用过则设置为null，下一次循环重新生成
            if (exist(poke)){
                poke = null;
            }else {
                addPoke(poke);
            }
        }
        return poke;
    }

    /**
     * 查询某一个轮中谁的牌最大，由他第一个下注
     * @param number
     * @return
     */
    public int whoMakeDecision(int number){
        int maxIndex = 0;
        int maxValue = 0;
        for (int i=0; i<gamers.size() ;i++){
            if (gamers.get(i).getPokeList().get(number).getIndex() > maxValue){
                maxIndex = i;
                maxValue = gamers.get(i).getPokeList().get(number).getIndex();
            }
        }
        return maxIndex;
    }




}
